package framework.transport.server;

import framework.enums.XMessageTypeEnum;
import framework.enums.XResponseCodeEnum;
import framework.handler.XRequestHandler;
import framework.transport.codec.XResponse;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import framework.transport.codec.XMessage;
import framework.transport.codec.XRequest;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;

import static io.netty.channel.ChannelFutureListener.CLOSE_ON_FAILURE;

@Slf4j
public class XServerHandler extends ChannelInboundHandlerAdapter {

    private final XRequestHandler xRequestHandler;

    public XServerHandler(XRequestHandler xRequestHandler) {
        this.xRequestHandler = xRequestHandler;
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        super.userEventTriggered(ctx, evt);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
    }


    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        XMessage xMessage = new XMessage();
        XRequest xRequest = null;
        try {
            if (!(msg instanceof XMessage)) {
                log.error("msg not instanceof XMessage");
                return;
            }
            xRequest = (XRequest) ((XMessage) msg).getData();
            xMessage.setRequestId((xRequest.getRequestId()));
            xMessage.setMessageType(XMessageTypeEnum.RESPONSE.getCode());
            xMessage.setCodec(((XMessage) msg).getCodec());
            xMessage.setCompress(((XMessage) msg).getCompress());
            Object result = xRequestHandler.handle(xRequest);
            log.debug("执行成功 requestId {} interfaceName {} methodName {} result{}",
                    xRequest.getRequestId(),
                    xRequest.getInterfaceName(),
                    xRequest.getMethodName(),
                    result != null ? result.toString() : "result is null");
            xMessage.setData(XResponse.success(result, xRequest.getRequestId()));
            if (!ctx.channel().isOpen()) {
                log.error("requestId [{}], 远程 通道未打开", xRequest.getRequestId());
                return;
            }
            if (!ctx.channel().isActive()) {
                log.error("requestId [{}], 远程 通道未活跃", xRequest.getRequestId());
                return;
            }
            if (!ctx.channel().isWritable()) {
                log.error("requestId [{}], 远程 通道不可写", xRequest.getRequestId());
                return;
            }
            ctx.writeAndFlush(xMessage).addListener(CLOSE_ON_FAILURE);
        } catch (Exception ex) {
            xMessage.setData(XResponse.fail(XResponseCodeEnum.FAIL, xMessage.getRequestId(), ex));
            ctx.writeAndFlush(xMessage).addListener(CLOSE_ON_FAILURE);
            assert xRequest != null;
            log.debug("执行失败 requestId {} interfaceName {} methodName {} result{}",
                    xRequest.getRequestId(),
                    xRequest.getInterfaceName(),
                    xRequest.getMethodName(),
                    ex.toString());
        } finally {
            ReferenceCountUtil.release(msg);
        }
    }
}
